package com.qire.antscompiler.generator;

import com.qire.antscompiler.utils.Log;
import com.qire.antscore.annotation.DeepLink;
import com.qire.antscore.common.AssertUtils;
import com.qire.antscore.entity.DeepLinkMeta;
import com.qire.antscore.entity.DeepLinkMeta.DeepLinkType;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;

/**
 * DeepLinkCode 生成器
 */
public class DeepLinkCodeGenerator {

    // 源文件构建存放路劲包名
    private final String PACKAGE_OF_GENERATE_FILE = "com.qire.antsdeeplink.registry";
    // 类名前缀，用于构建方法代码
    private final String CLASS_NAME_PREFIX = "DispatchRegistry";
    // 协议匹配方法名，用于构建方法代码
    private final String METHOD_MATCH_SCHEME = "matchScheme";
    // 查找处理器方法名，用于构建方法代码
    private final String METHOD_FIND_HANDLER = "findHandler";


    // Activity 全类名，用于获取类型映射类型镜像
    private final String ACTIVITY = "android.app.Activity";
    // AntsRouter 全类名，用于获取类型映射类型镜像
    private final String ANTS_ROUTER = "com.qire.antsrouter.AntsRouter";
    // DeepLinkUri 全类名，用于获取类型映射类型镜像
    private final String DEEP_LINK_URI = "com.qire.antsdeeplink.DeepLinkUri";
    // DeepLinkHandler 全类名，用于获取类型映射类型镜像
    private final String DEEP_LINK_HANDLER = "com.qire.antsdeeplink.DeepLinkHandler";
    // DeepLinkDispatchRegistry 全类名，用于获取类型映射类型镜像
    private final String DISPATCH_REGISTRY = "com.qire.antsdeeplink.DeepLinkDispatchRegistry";
    // Activity 类型镜像
    private final TypeMirror typeActivity;
    // DeepLinkUri 类型
    private final TypeMirror typeDeepLinkUri;


    // 日志
    private final Log log;

    // type(类信息)工具类
    private final Types typeUtils;

    // 文件生成器 类/资源
    private final Filer filerUtils;

    // 节点工具类 (类、函数、属性都是节点)
    private final Elements elementUtils;

    private final ArrayList<DeepLinkMeta> metaList = new ArrayList<>();

    private final HashMap<String, ArrayList<DeepLinkMeta>> groupElement = new HashMap<>();

    public DeepLinkCodeGenerator(ProcessingEnvironment processingEnv) {
        this.log = Log.newLog(processingEnv.getMessager());
        this.typeUtils = processingEnv.getTypeUtils();
        this.filerUtils = processingEnv.getFiler();
        this.elementUtils = processingEnv.getElementUtils();

        // 获得 Activity 类的类型反射
        typeActivity = elementUtils.getTypeElement(ACTIVITY).asType();
        // 获得 DeepLinkUri 类的反射镜像
        typeDeepLinkUri = elementUtils.getTypeElement(DEEP_LINK_URI).asType();
    }

    /**
     * 注解解析处理
     * @param elements 所有注解标注过的类
     */
    public void parseDeepLink(Set<? extends Element> elements) {
        if(AssertUtils.isEmpty(elements)) {
            log.i("DeepLinkCodeGenerator：elements 为空没有需要处理的");
            return;
        }
        log.i("DeepLinkCodeGenerator：开始处理了！");

        // 解析所有的注解，整理出 DeepLinkMeta 列表
        fillMetaList(elements);

        // 按 scheme 分组排序
        metaSortByGroup();

        // 检查解析分组结果
        if(AssertUtils.isEmpty(groupElement)) {
            log.i("DeepLinkCodeGenerator：groupElement 为空没有解析到需要处理的url");
            return;
        }

        // 获得 Router 框架路由器
        TypeElement typeAntsRouter = elementUtils.getTypeElement(ANTS_ROUTER);
        boolean isImportRouter  = AssertUtils.nonNull(typeAntsRouter);

        // 获得 DeepLinkHandler 类的反射镜像
        TypeMirror typeDeepLinkHandler = elementUtils.getTypeElement(DEEP_LINK_HANDLER).asType();

        // 获得 DeepLinkDispatchRegistry 类的反射镜像
        TypeMirror typeDispatchRegistry = elementUtils.getTypeElement(DISPATCH_REGISTRY).asType();


        for (Map.Entry<String, ArrayList<DeepLinkMeta>> entry : groupElement.entrySet()) {

            ArrayList<DeepLinkMeta> metaGroupList = entry.getValue();

            if(AssertUtils.isEmpty(metaGroupList)) {
                continue;
            }

            String schemeStr = entry.getKey();

            // 构建注册表，实现一个基于 DeepLinkDispatchRegistry 的注册表类，用于路由查询：

            // 1、构建 public abstract boolean matchScheme(String scheme); 方法
            MethodSpec.Builder matchSchemeMethodBuilder = generatedMatchSchemeMethod(schemeStr);

            // 2、构建 public abstract DeepLinkHandler findHandler(DeepLinkUri deepLinkUri); 方法
            MethodSpec.Builder findHandlerMethodBuilder = generatedFindHandlerMethod(typeDeepLinkHandler, metaGroupList, isImportRouter);


            schemeStr = "*".equals(schemeStr) ? "All" : schemeStr;
            // 生成java类名
            String newDispatchRegistryClassName = CLASS_NAME_PREFIX + schemeStr.substring(0, 1).toUpperCase() + schemeStr.substring(1);

            // 构建一个 public class ****DispatchRegistry extends DeepLinkDispatchRegistry {} 类
            TypeSpec DalExceptionObserveBinderClass = TypeSpec.classBuilder(newDispatchRegistryClassName)
                    .addModifiers(Modifier.PUBLIC)
                    .addMethod(matchSchemeMethodBuilder.build())
                    .addMethod(findHandlerMethodBuilder.build())
                    .superclass(ClassName.get(typeDispatchRegistry))
                    .build();

            //将 ****DispatchRegistry 文件写入磁盘中,路径是在app/build/source/api/debug/下面
            try {
                JavaFile.builder(PACKAGE_OF_GENERATE_FILE, DalExceptionObserveBinderClass).build().writeTo(filerUtils);
            } catch (IOException e) {
                e.printStackTrace();
            }

            log.i("DeepLinkCodeGenerator 构建成功: " + PACKAGE_OF_GENERATE_FILE + "." + newDispatchRegistryClassName);
        }

        log.i("DeepLinkCodeGenerator：结束处理了！");
    }

    /**
     * 整理 DeepLinkMeta 列表
     * @param elements 解析元素
     */
    private void fillMetaList(Set<? extends Element> elements) {
        for(Element element : elements) {
            DeepLink deepLink = element.getAnnotation(DeepLink.class);

            // 被注解标注元素类的类型反射
            TypeMirror typeMirror = element.asType();

            // 检查这个注解标注类的类型是否是 Activity
            DeepLinkType linkType = typeUtils.isSubtype(typeMirror, typeActivity) ? DeepLinkType.Page : DeepLinkType.Action;

            DeepLinkMeta meta = DeepLinkMeta.parsePath(element, linkType, deepLink.path());
            log.i("DeepLinkMeta :==========" + meta);

            metaList.add(meta);
        }
    }

    /**
     * 对处理数据元分组排序
     */
    private void metaSortByGroup() {
        for(DeepLinkMeta meta : metaList) {
            String groupKey = AssertUtils.isEmpty(meta.scheme()) ? "*" : meta.scheme();

            ArrayList<DeepLinkMeta> metaGroupList = groupElement.get(groupKey);
            if(AssertUtils.isEmpty(metaGroupList)) {
                metaGroupList = new ArrayList<>();
                groupElement.put(groupKey, metaGroupList);
            }
            metaGroupList.add(meta);
        }
    }

    /**
     * 构建 public abstract boolean matchScheme(String scheme); 方法
     * @param schemeStr
     * @return
     */
    private MethodSpec.Builder generatedMatchSchemeMethod(String schemeStr) {
        // 1.1、申明变量 String scheme
        ParameterSpec schemeSpec = ParameterSpec.builder(String.class, "scheme").build();
        // 1.2、定义方法 matchScheme(String scheme)
        MethodSpec.Builder matchSchemeMethodBuilder = MethodSpec.methodBuilder(METHOD_MATCH_SCHEME)
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PUBLIC)
                .returns(boolean.class)
//                    .addModifiers(Modifier.STATIC)
                .addParameter(schemeSpec);
        // 1.3、写入函数体
        matchSchemeMethodBuilder.addStatement("return \"$L\".equals(scheme)", schemeStr);
        return matchSchemeMethodBuilder;
    }

    /**
     * 构建 public abstract DeepLinkHandler findHandler(DeepLinkUri deepLinkUri); 方法
     * @param typeDeepLinkHandler
     * @param metaGroupList
     * @param isImportRouter
     * @return
     */
    private MethodSpec.Builder generatedFindHandlerMethod(TypeMirror typeDeepLinkHandler, ArrayList<DeepLinkMeta> metaGroupList, boolean isImportRouter) {
        // 2.1、申明变量 DeepLinkUri deepLinkUri
        ParameterSpec deepLinkUriSpec = ParameterSpec.builder(ClassName.get(typeDeepLinkUri), "deepLinkUri").build();
        // 2.2、定义方法 DeepLinkHandler findHandler(DeepLinkUri deepLinkUri)
        MethodSpec.Builder findHandlerMethodBuilder = MethodSpec.methodBuilder(METHOD_FIND_HANDLER)
                .addAnnotation(Override.class)
                .addModifiers(Modifier.PUBLIC)
                .returns(ClassName.get(typeDeepLinkHandler))
//                    .addModifiers(Modifier.STATIC)
                .addParameter(deepLinkUriSpec);
        // 2.3、写入函数体
        findHandlerMethodBuilder.addStatement("String hostFullPath = deepLinkUri.fullPathUseToMatch()");
        findHandlerMethodBuilder.addCode("switch (hostFullPath) {\n");
        for (DeepLinkMeta meta : metaGroupList) {
            if(meta.linkType == DeepLinkType.Page) {
                // 如果是 Activity 则归入页面跳转行为
                generatedGotoActivity(meta, findHandlerMethodBuilder, isImportRouter);
            } else {
                // 如果不是 Activity 则归入方法执行
                generatedGotoProcessor(meta, findHandlerMethodBuilder, isImportRouter);
            }
        }
        findHandlerMethodBuilder.addStatement("    default : return null");
        findHandlerMethodBuilder.addCode("}\n");

        return findHandlerMethodBuilder;
    }

    /**
     * 生成跳转Activity的行为代码
     * @param deepLinkMeta
     * @param findHandlerMethodBuilder
     * @param isImportRouter
     */
    private void generatedGotoActivity(DeepLinkMeta deepLinkMeta, MethodSpec.Builder findHandlerMethodBuilder, boolean isImportRouter) {
        if(isImportRouter) {
            /** FloorCard floorCard = AntsRouter.ROUTER.buildCard(path);
             *  for(String queryName : queryNames) {
             *      floorCard.withData(queryName, deepLinkUri.queryValue(queryName));
             *  }
             *  floorCard.navigation(); */
//            findHandlerMethodBuilder.addStatement("    FloorCard floorCard = AntsRouter.ROUTER.buildCard(path)");
        } else {
            TypeName actionClass = ClassName.get(deepLinkMeta.element.asType());
            /** Intent intent = new Intent();
             *  intent.setClass();
             *  activity.startIntent(intent); */
        }
    }

    /**
     * 生成处理过程的行为代码
     * @param deepLinkMeta
     * @param findHandlerMethodBuilder
     * @param isImportRouter
     */
    private void generatedGotoProcessor(DeepLinkMeta deepLinkMeta, MethodSpec.Builder findHandlerMethodBuilder, boolean isImportRouter) {

        TypeName actionClass = ClassName.get(deepLinkMeta.element.asType());

        List<? extends Element>  subElementList = deepLinkMeta.element.getEnclosedElements();

        // todo：需要过滤去重
        for(Element subElement : subElementList) {
            // 匹配检测方法签名，如果签名不正确则跳过
            if(matchActionElement(subElement)) {
                String actionName = subElement.getSimpleName().toString();
                String actionCase = deepLinkMeta.fullPathUseToMatch() + "/" + actionName;

                if(subElement.getModifiers().contains(Modifier.STATIC)) {
                    // case "tag" : return DeepLinkHandler::action;
                    findHandlerMethodBuilder.addStatement("    case \"$L\" : return $T::$L", actionCase, actionClass, actionName);
                } else {
                    // case "tag" : return new DeepLinkHandler()::action;
                    findHandlerMethodBuilder.addStatement("    case \"$L\" : return new $T()::$L", actionCase, actionClass, actionName);
                }
            }
        }
    }

    /**
     * 匹配 Element 是否符合构建 Action条件，如果 Element 是方法，且方法的签名符合 DeepLinkHandler 接口规范则构建
     * @param element
     * @return true 可以构建 false 不符合规范
     */
    private boolean matchActionElement(Element element) {
        log.i(String.format("subElement 方法有: %s,  %s,  %s", element.getSimpleName(), element.asType(), element.toString()));
        // 检查是不是方法
        if(ElementKind.METHOD != element.getKind()) {
            return false;
        }
        // 检查方法的签名：参数是否符合
        List<? extends TypeMirror> parameterTypes = ((ExecutableType) element.asType()).getParameterTypes();
        if(AssertUtils.isEmpty(parameterTypes) || parameterTypes.size() >= 2) {
            return false;
        }
        return typeDeepLinkUri.equals(parameterTypes.get(0));
        // todo: 理论上还需要检查返回值
    }

    /**
     * 匹配无参构造函数
     * @param element
     * @return
     */
    private boolean matchConstructor(Element element) {
        List<? extends Element>  subElementList = element.getEnclosedElements();
        for(Element subElement : subElementList) {
            if(ElementKind.CONSTRUCTOR == subElement.getKind()) {
                ExecutableType executableType = (ExecutableType) subElement.asType();
                if(AssertUtils.isEmpty(executableType.getParameterTypes())) {
                    return true;
                }
            }
        }
        return false;
    }

}
